package com.ms.common.reflect;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zdh
 */
public class BeanToMapConverter implements Cloneable {

    public static Map<String, Object> beanToMap(Object obj) {
        if (obj == null) {
            return Collections.emptyMap();
        }

        // Handle List and arrays
        if (obj instanceof List || obj.getClass().isArray()) {
            List<?> list = obj instanceof List ? (List<?>) obj : Arrays.asList((Object[]) obj);
            return Collections.singletonMap("items", list.stream()
                    .map(BeanToMapConverter::beanToMap)
                    .collect(Collectors.toList()));
        }

        // Handle Map
        if (obj instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) obj;
            return map.entrySet().stream()
                    .collect(Collectors.toMap(
                            entry -> String.valueOf(entry.getKey()),
                            entry -> beanToMap(entry.getValue())
                    ));
        }

        // Handle Bean objects
        BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
        PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();

        Map<String, Object> resultMap = new HashMap<>();
        for (PropertyDescriptor pd : propertyDescriptors) {
            String propertyName = pd.getName();
            if ("class".equals(propertyName)) {
                continue; // Ignore the "class" property
            }
            try {
                Object propertyValue = beanWrapper.getPropertyValue(propertyName);
                resultMap.put(propertyName, beanToMap(propertyValue));
            } catch (Exception ignored) {
                // Handle exceptions as needed
            }
        }
        return resultMap;
    }

    public static Map<String, Object> beanToMapIgnoreNullValue(Object obj) {
        if (obj == null) {
            return Collections.emptyMap();
        }

        // Handle List and arrays
        if (obj instanceof List || obj.getClass().isArray()) {
            List<?> list = obj instanceof List ? (List<?>) obj : Arrays.asList((Object[]) obj);
            return Collections.singletonMap("items", list.stream()
                    // Ignore null elements in lists/arrays
                    .filter(Objects::nonNull)
                    .map(BeanToMapConverter::beanToMapIgnoreNullValue)
                    .collect(Collectors.toList()));
        }

        // Handle Map
        if (obj instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) obj;
            return map.entrySet().stream()
                    // Ignore null values in maps
                    .filter(entry -> entry.getValue() != null)
                    .collect(Collectors.toMap(
                            entry -> String.valueOf(entry.getKey()),
                            entry -> beanToMap(entry.getValue())
                    ));
        }
        // Handle Bean objects
        BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
        PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();

        Map<String, Object> resultMap = new HashMap<>();
        for (PropertyDescriptor pd : propertyDescriptors) {
            String propertyName = pd.getName();
            if ("class".equals(propertyName)) {
                continue; // Ignore the "class" property
            }
            try {
                Object propertyValue = beanWrapper.getPropertyValue(propertyName);
                // Only add non-null properties to the result map
                if (propertyValue != null) {
                    resultMap.put(propertyName, beanToMapIgnoreNullValue(propertyValue));
                }
            } catch (Exception ignored) {
                // Handle exceptions as needed
            }
        }
        return resultMap;
    }

    // 示例用法
    public static void main(String[] args) {
        Person person = new Person("John", 30);
        List<Person> people = Arrays.asList(person, null, new Person("Jane", 25)); // 包含一个null元素
        Map<String, Object> complexMap = new HashMap<>();
        complexMap.put("person", person);
        complexMap.put("people", people);
        complexMap.put("empty", null); // 添加一个null值键

        System.out.println(beanToMap(person)); // 输出单个Person对象转换后的Map
        System.out.println(beanToMap(people)); // 输出List<Person>转换后的Map，忽略null元素
        System.out.println(beanToMap(complexMap)); // 输出包含Bean、List和null值的Map转换后的Map，忽略null值
    }
    static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        // Getters and Setters are required here
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}
